package x10.enums;

import java.util.EnumSet;
import java.util.HashMap;

/**
 *  Device - enumeration of device codes (1-16) along with utility methods
 *  to create the nibble values for powerline and radio frequency versions
 *  and static methods for creating a device object
 *
 *  @author Denny Sheirer
 *  @date   20110124
 */

public enum Device {

    D1(6,6,1),
    D2(14,7,2),
    D3(2,4,3),
    D4(10,5,4),
    D5(1,8,5),
    D6(9,9,6),
    D7(5,10,7),
    D8(13,11,8),
    D9(7,14,9),
    D10(15,15,10),
    D11(3,12,11),
    D12(11,13,12),
    D13(0,0,13),
    D14(8,1,14),
    D15(4,2,15),
    D16(12,3,16),
    DUNK(17,17,17);

    private final int powerline;   //Device code int value little endian
    private final int radioFrequency;   //Device code int value big endian
    private final int ordinal;   //Device code int value where int == code

    //Lookups to convert from integer to Device code
    private static final HashMap<Integer,Device> powerlineLookup = new HashMap<Integer,Device>();
    private static final HashMap<Integer,Device> radioFrequencyLookup = new HashMap<Integer,Device>();
    private static final HashMap<Integer,Device> ordinalLookup = new HashMap<Integer,Device>();

    //Constructor hidden class to populate the lookup hashmaps
    static {
        for(Device d : EnumSet.allOf(Device.class)){
            powerlineLookup.put(d.powerline, d);
            radioFrequencyLookup.put(d.radioFrequency, d);
            ordinalLookup.put(d.ordinal, d);
        }
    }

    /**
     * Constructor - X10 Device code object
     * 
     * Used to construct three hashmaps with lookup values to support
     * utility static methods
     * 
     * @param powerline
     * @param radioFrequency
     * @param ordinal
     */
    Device(int powerline, int radioFrequency, int ordinal){
        this.powerline = powerline;
        this.radioFrequency = radioFrequency;
        this.ordinal = ordinal;
    }

    /**
     * Utility method to return byte with device code in lower nibble, representing
     * the powerline version of the device code
     * @return
     */
    public byte getPowerlineVersion(){
        return (byte) powerline;
    }

    /**
     * Utility method to return byte with device code in lower nibble, representing
     * the radio frequency version of the device code
     * @return
     */
    public byte getRadioFrequencyVersion(){
        return (byte) radioFrequency;
    }

    /**
     * Utility method to return the ordinal value (zero-based) of the device object
     * @return
     */
    public byte getOrdinal(){
        return (byte) ((ordinal - 1) & 0xFF);
    }

    /**
     * Method to get Device object from powerline version of device address
     * Convert device nibble value to an integer
     *
     * @param device - integer value of device nibble for powerline address
     * @return - Device object
     */
    public static Device getDeviceFromPowerline(int device){
        return powerlineLookup.get(device);
    }

    /**
     * Method to get Device object from radio frequency version of the device
     * address.  Convert device nibble value to an integer
     *
     * Note: majority of the radio frequency versions use the ordinal method
     * instead of this bit-reversed version of the powerline device version
     *
     * @param device
     * @return - Device object
     */
    public static Device getDeviceFromRadioFrequency(int device){
        return radioFrequencyLookup.get(device);
    }

    /**
     * Method to get Device object from radio frequency ordinal value
     * Convert ordinal nibble value and pass (zero-based index) to method
     * 
     * @param device - zero based device ordinal value
     * @return - Device object
     */
    public static Device getDeviceFromOrdinal(int device){
        return ordinalLookup.get(device);
    }

    /**
     * Utility method to return string representation of the device number
     * @return String representation of device number
     */
    @Override
    public String toString(){
        return this.name().substring(1);
    }

}
